#include <stdio.h>
#include <string.h>
#include "tsocket.h"
#include "tbuffer.h"
tlib::TBufferPool* g_bufferPool = new tlib::TBufferPool;
namespace tlib
{
struct STBlock
{
	char buffer[BLOCK_SIZE];
};
TBufferPool::TBufferPool()
{
	m_pAllBlock = new STBlock[BLOCK_COUNT];
	for (int i = 0; i < BLOCK_COUNT; i++)
		m_nNoUseBlock.push_back(i);
}

TBufferPool::~TBufferPool()
{
	delete[] m_pAllBlock;
}

int TBufferPool::AllocBlock()
{
	TAutoLock lock(&m_mutex);
	int blockNo = m_nNoUseBlock.back();
	m_nNoUseBlock.pop_back();
	return blockNo;
}

void TBufferPool::FreeBlock(int blockNo)
{
	TAutoLock lock(&m_mutex);
	m_nNoUseBlock.push_back(blockNo);
}

STBlock* TBufferPool::GetBlock(int blockNo)
{
	STBlock* st = &m_pAllBlock[blockNo];
	return st;
}

TBuffer::TBuffer() :
	m_nReadIdx(0), m_nWriteIdx(0), m_nReadNo(-1), m_nWriteNo(-1)
{

}

TBuffer::~TBuffer()
{
	for (unsigned int i = 0; i < blocks_.size(); i++)
	{
		bufferPool_->FreeBlock(blocks_[i]);
	}
}

void TBuffer::Bind(TBufferPool* pool)
{
	bufferPool_ = pool;
}

bool TBuffer::Read(char* buff, int len, bool del)
{
//	TAutoLock lock(&m_mutex);
	if (blocks_.empty() || len <= 0)
		return false;
	if ((m_nWriteNo * BLOCK_SIZE + m_nWriteIdx) - (m_nReadNo * BLOCK_SIZE + m_nReadIdx) < len)
		return false;
	int oldReadNo = m_nReadNo, oldReadIdx = m_nReadIdx;
	for (; len > 0;)
	{
		STBlock* st = bufferPool_->GetBlock(blocks_[m_nReadNo]);
		int ableReadLen = m_nWriteNo > m_nReadNo ? BLOCK_SIZE - m_nReadIdx : m_nWriteNo == m_nReadNo ? m_nWriteIdx - m_nReadIdx : 0;
		ableReadLen = ableReadLen > len ? len : ableReadLen;
		if (ableReadLen > 0)
		{
			memcpy(buff, &st->buffer[m_nReadIdx], ableReadLen);
			buff += ableReadLen;
			len -= ableReadLen;
			m_nReadIdx += ableReadLen;
			if (m_nReadIdx == BLOCK_SIZE)
			{
				m_nReadNo++;
				m_nReadIdx = 0;
			}
		}
	}
	if (del)
	{
		for (; m_nReadNo > 0 || (0 == m_nReadNo && 0 == m_nWriteNo && m_nReadIdx == m_nWriteIdx);)
		{
			m_nReadNo--;
			m_nWriteNo--;
			bufferPool_->FreeBlock(*blocks_.begin());
			blocks_.erase(blocks_.begin());
		}
	}
	else
	{
		m_nReadNo = oldReadNo;
		m_nReadIdx = oldReadIdx;
	}
	return true;
}

bool TBuffer::Write(char* buff, int len)
{
//	TAutoLock lock(&m_mutex);
	if (blocks_.empty())
	{
		blocks_.push_back(bufferPool_->AllocBlock());
		m_nReadNo = 0;
		m_nWriteNo = 0;
	}
	for (; len > 0;)
	{
		STBlock* st = bufferPool_->GetBlock(blocks_[m_nWriteNo]);
		int ableWriteLen = BLOCK_SIZE - m_nWriteIdx;
		ableWriteLen = ableWriteLen > len ? len : ableWriteLen;
		if (ableWriteLen > 0)
		{
			memcpy(&st->buffer[m_nWriteIdx], buff, ableWriteLen);
			buff += ableWriteLen;
			len -= ableWriteLen;
			m_nWriteIdx += ableWriteLen;
			if (m_nWriteIdx == BLOCK_SIZE && m_nWriteNo == blocks_.size() - 1)
			{
				blocks_.push_back(bufferPool_->AllocBlock());
				m_nWriteNo++;
				m_nWriteIdx = 0;
			}
		}
	}
	return true;
}

int TBuffer::ReadFd(int srcfd, int len)
{
//	TAutoLock lock(&m_mutex);
	if (blocks_.empty())
	{
		blocks_.push_back(bufferPool_->AllocBlock());
		m_nReadNo = 0;
		m_nWriteNo = 0;
	}
	int realLen = 0;
	for (; realLen < len;)
	{
		STBlock* st = bufferPool_->GetBlock(blocks_[m_nWriteNo]);
		int ableWriteLen = BLOCK_SIZE - m_nWriteIdx;
		ableWriteLen = ableWriteLen > len ? len : ableWriteLen;
		if (ableWriteLen > 0)
		{
			int realWriteLen = TSocket::Recv(srcfd, &st->buffer[m_nWriteIdx], ableWriteLen);
			if (realWriteLen <= 0)
				return realWriteLen == -1 ? -1 : realLen;
			realLen += realWriteLen;
			m_nWriteIdx += realWriteLen;
			if (m_nWriteIdx == BLOCK_SIZE && m_nWriteNo == blocks_.size() - 1)
			{
				blocks_.push_back(bufferPool_->AllocBlock());
				m_nWriteNo++;
				m_nWriteIdx = 0;
			}
		}
	}
	return realLen;
}

int TBuffer::GetAllLength()
{
	return (m_nWriteNo * BLOCK_SIZE + m_nWriteIdx) - (m_nReadNo * BLOCK_SIZE + m_nReadIdx);
}

int TBuffer::GetEnterLength()
{
	return 0;
}
}//namespace tlib
